package com.starhub.engine.ai.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starhub.application.function.enums.AiFunctionStatusEnum;
import com.starhub.application.interfaces.function.IAiFunctionService;
import com.starhub.common.bean.agent.AiFunction;
import com.starhub.engine.ai.dao.mapper.AiFunctionMapper;
import com.starhub.engine.ai.dto.AiFunctionDTO;
import com.starhub.engine.ai.vo.AiFunctionVO;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * AI函数服务实现类
 */
@Slf4j
@Service
public class AiFunctionServiceImpl extends ServiceImpl<AiFunctionMapper, AiFunction> implements IAiFunctionService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addFunction(AiFunctionDTO functionDTO, String operatorId, String operatorName) {
        // 检查函数名称是否已存在
        long count = this.count(new LambdaQueryWrapper<AiFunction>()
                .eq(AiFunction::getName, functionDTO.getName()));
        if (count > 0) {
            throw new RuntimeException("函数名称已存在");
        }

        AiFunction function = new AiFunction();
        BeanUtils.copyProperties(functionDTO, function);

        // 设置默认值
        if (function.getStatus() == null) {
            function.setStatus(AiFunctionStatusEnum.ENABLED.getCode());
        }

        // 设置创建人信息
        setCreatorInfo(function, operatorId, operatorName);

        function.setCreateTime(LocalDateTime.now());
        function.setUpdateTime(LocalDateTime.now());

        return this.save(function);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateFunction(AiFunctionDTO functionDTO, String operatorId, String operatorName) {
        if (functionDTO.getId() == null) {
            throw new RuntimeException("函数ID不能为空");
        }

        // 检查函数是否存在
        AiFunction existingFunction = this.getById(functionDTO.getId());
        if (existingFunction == null) {
            throw new RuntimeException("函数不存在");
        }

        // 检查函数名称是否已存在（排除自身）
        long count = this.count(new LambdaQueryWrapper<AiFunction>()
                .eq(AiFunction::getName, functionDTO.getName())
                .ne(AiFunction::getId, functionDTO.getId()));
        if (count > 0) {
            throw new RuntimeException("函数名称已存在");
        }

        AiFunction function = new AiFunction();
        BeanUtils.copyProperties(functionDTO, function);

        // 设置更新人信息
        setUpdaterInfo(function, operatorId, operatorName);

        function.setUpdateTime(LocalDateTime.now());

        return this.updateById(function);
    }

    /**
     * 设置创建人信息
     * 
     * @param function     AI函数实体
     * @param operatorId   操作人ID
     * @param operatorName 操作人姓名
     */
    private void setCreatorInfo(AiFunction function, String operatorId, String operatorName) {
        if (StringUtils.isNotBlank(operatorId) && StringUtils.isNotBlank(operatorName)) {
            function.setCreatorId(operatorId);
            function.setCreatorName(operatorName);
            // 同时设置更新人信息，初始值与创建人相同
            function.setUpdaterId(operatorId);
            function.setUpdaterName(operatorName);
        } else {
            // 默认值，防止空值异常
            function.setCreatorId("system");
            function.setCreatorName("系统");
            function.setUpdaterId("system");
            function.setUpdaterName("系统");
        }
    }

    /**
     * 设置更新人信息
     * 
     * @param function     AI函数实体
     * @param operatorId   操作人ID
     * @param operatorName 操作人姓名
     */
    private void setUpdaterInfo(AiFunction function, String operatorId, String operatorName) {
        if (StringUtils.isNotBlank(operatorId) && StringUtils.isNotBlank(operatorName)) {
            function.setUpdaterId(operatorId);
            function.setUpdaterName(operatorName);
        } else {
            // 默认值，防止空值异常
            function.setUpdaterId("system");
            function.setUpdaterName("系统");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteFunction(Long id) {
        return this.removeById(id);
    }

    @Override
    public AiFunctionVO getFunctionDetail(Long id) {
        AiFunction function = this.getById(id);
        if (function == null) {
            return null;
        }

        AiFunctionVO vo = new AiFunctionVO();
        BeanUtils.copyProperties(function, vo);
        vo.setId(function.getId().toString());
        return vo;
    }

    @Override
    public IPage<AiFunctionVO> pageFunctions(int page, int size, String name, String type) {
        LambdaQueryWrapper<AiFunction> queryWrapper = new LambdaQueryWrapper<>();

        // 添加查询条件
        if (StringUtils.isNotBlank(name)) {
            queryWrapper.like(AiFunction::getName, name);
        }
        if (StringUtils.isNotBlank(type)) {
            queryWrapper.eq(AiFunction::getType, type);
        }

        // 排序
        queryWrapper.orderByDesc(AiFunction::getCreateTime);

        // 分页查询
        Page<AiFunction> pageResult = this.page(new Page<>(page, size), queryWrapper);

        // 转换结果
        IPage<AiFunctionVO> voPage = new Page<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
        List<AiFunctionVO> voList = pageResult.getRecords().stream().map(function -> {
            AiFunctionVO vo = new AiFunctionVO();
            BeanUtils.copyProperties(function, vo);
            vo.setId(function.getId().toString());
            return vo;
        }).collect(Collectors.toList());
        voPage.setRecords(voList);

        return voPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean enableFunction(Long id, String operatorId, String operatorName) {
        AiFunction function = this.getById(id);
        if (function == null) {
            throw new RuntimeException("函数不存在");
        }

        function.setStatus(AiFunctionStatusEnum.ENABLED.getCode());

        // 设置更新人信息
        if (StringUtils.isNotBlank(operatorId) && StringUtils.isNotBlank(operatorName)) {
            function.setUpdaterId(operatorId);
            function.setUpdaterName(operatorName);
        } else {
            function.setUpdaterId("system");
            function.setUpdaterName("系统");
        }

        function.setUpdateTime(LocalDateTime.now());

        return this.updateById(function);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean disableFunction(Long id, String operatorId, String operatorName) {
        AiFunction function = this.getById(id);
        if (function == null) {
            throw new RuntimeException("函数不存在");
        }

        function.setStatus(AiFunctionStatusEnum.DISABLED.getCode());

        // 设置更新人信息
        if (StringUtils.isNotBlank(operatorId) && StringUtils.isNotBlank(operatorName)) {
            function.setUpdaterId(operatorId);
            function.setUpdaterName(operatorName);
        } else {
            function.setUpdaterId("system");
            function.setUpdaterName("系统");
        }

        function.setUpdateTime(LocalDateTime.now());

        return this.updateById(function);
    }

    @Override
    public List<Object> getEnabledFunctionSpecifications() {
        // 查询所有启用状态的函数
        List<AiFunction> functions = this.list(new LambdaQueryWrapper<AiFunction>()
                .eq(AiFunction::getStatus, AiFunctionStatusEnum.ENABLED.getCode()));

        // 将函数转换为工具规格
        List<Object> toolSpecifications = new ArrayList<>();

        for (AiFunction function : functions) {
            // 这里需要根据实际需要将函数转换为langchain4j的ToolSpecification对象
            // 由于导入问题，先返回基础的Map对象
            Map<String, Object> spec = new HashMap<>();
            spec.put("name", function.getName());
            spec.put("description", function.getDescription());
            spec.put("parameters", JSON.parse(function.getParameters()));

            toolSpecifications.add(spec);
        }

        return toolSpecifications;
    }

    @Override
    public String executeFunction(String functionName, Map<String, Object> arguments) {
        try {
            // 查询函数信息
            AiFunction function = this.getOne(new LambdaQueryWrapper<AiFunction>()
                    .eq(AiFunction::getName, functionName)
                    .eq(AiFunction::getStatus, AiFunctionStatusEnum.ENABLED.getCode()));

            if (function == null) {
                return "函数 " + functionName + " 不存在或已禁用";
            }

            // 获取实现类
            String className = function.getImplementationClass();
            String methodName = function.getImplementationMethod();

            // 动态加载类
            Class<?> clazz = Class.forName(className);
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // 解析参数类型和参数值
            JSONObject paramsConfig = JSON.parseObject(function.getParameters());
            JSONObject properties = paramsConfig.getJSONObject("properties");

            // 准备方法参数
            List<Class<?>> paramTypes = new ArrayList<>();
            List<Object> paramValues = new ArrayList<>();

            // 遍历参数配置，匹配方法参数
            for (String paramName : properties.keySet()) {
                JSONObject paramConfig = properties.getJSONObject(paramName);
                String paramType = paramConfig.getString("type");

                // 转换参数类型
                Class<?> paramClass = getClassFromType(paramType);
                paramTypes.add(paramClass);

                // 获取参数值
                Object paramValue = arguments.get(paramName);
                if(Objects.isNull(paramValue) && paramConfig.containsKey("default")) {
                    paramValue = paramConfig.get("default");
                }

                // 类型转换
                if (paramClass == Integer.class && paramValue instanceof Number) {
                    paramValue = ((Number) paramValue).intValue();
                } else if (paramClass == Double.class && paramValue instanceof Number) {
                    paramValue = ((Number) paramValue).doubleValue();
                } else if (paramClass == Boolean.class && paramValue instanceof String) {
                    paramValue = Boolean.parseBoolean((String) paramValue);
                }

                paramValues.add(paramValue);
            }

            // 获取并调用方法
            Method method = clazz.getMethod(methodName, paramTypes.toArray(new Class[0]));
            Object result = method.invoke(instance, paramValues.toArray());

            return result != null ? result.toString() : "null";
        } catch (Exception e) {
            log.error("执行函数失败", e);
            return "执行函数失败: " + e.getMessage();
        }
    }

    @Override
    public String regenerateWithFunctionResult(ChatLanguageModel model, String userMessage, String functionName,
            Map<String, Object> arguments, String result) {
        try {
            // 创建包含原始用户消息和函数调用结果的请求
            String systemPrompt = "用户使用了函数 " + functionName + "，参数是 " + JSON.toJSONString(arguments) + "，" +
                    "函数返回结果是: " + result + "。请根据函数执行结果给出一个完整、准确、有帮助的回复。";

            String fullPrompt = systemPrompt + "\n\n用户原始消息: " + userMessage;

            // 调用模型生成回复
            String response = model.generate(fullPrompt);

            return response;
        } catch (Exception e) {
            log.error("重新生成回复失败", e);
            return "无法根据函数结果生成回复: " + e.getMessage();
        }
    }

    /**
     * 根据类型字符串获取对应的Class对象
     */
    private Class<?> getClassFromType(String type) {
        switch (type.toLowerCase()) {
            case "string":
                return String.class;
            case "integer":
                return Integer.class;
            case "number":
                return Double.class;
            case "boolean":
                return Boolean.class;
            case "object":
                return Map.class;
            case "array":
                return List.class;
            default:
                return String.class;
        }
    }
}